/*\
|*| chatabase JSON request 'client' tests
|*|
|*| this suite depends on the 'setup' suite to clear remnant clients from the db
\*/


// runtime switches
integer DEBUG_EVS = FALSE ;

// suite-specific test data
string  SUITE_NAME    = "clients" ;
string  RESOURCE_PATH = "/clients.json" ;
list    FIXTURES ;   // prepareTestFixures()
integer N_FIXTURES ; // prepareTestFixures()

// shared project-specific constants
string  GRID_NAME ;      // loadSharedData()
string  REGION_NAME ;    // loadSharedData()
string  PARCEL_NAME ;    // loadSharedData()
string  ID_SENTINAL ;    // loadSharedData()
string  EXCEPTION_RESP ; // loadSharedData()
string  SECRET_RESP ;    // loadSharedData()
string  OWNER_NAME ;     // loadSharedData()
string  CLIENT_NAME ;   // loadSharedData() // unused here
string  DUPLICATES_RESP = "{\"secret\":\"exists\",\"room_secret\":\"" ;
string  CHANNEL_2_NAME  = "GridName Region_Name Parcel_Name" ; // ASSERT: corresponds to TEST_DUP_CLIENT_NAME server constant
integer GRID_IDX        = -1 ;    // ASSERT: negative int NOT DATA_LOAD_IDX
integer REGION_IDX      = -2 ;    // ASSERT: negative int NOT DATA_LOAD_IDX
integer PARCEL_IDX      = -3 ;    // ASSERT: negative int NOT DATA_LOAD_IDX
integer SENTINEL_IDX    = -4 ;    // ASSERT: negative int NOT DATA_LOAD_IDX
integer EXCEPTION_IDX   = -5 ;    // ASSERT: negative int NOT DATA_LOAD_IDX
integer SECRET_IDX      = -6 ;    // ASSERT: negative int NOT DATA_LOAD_IDX
integer OWNER_IDX       = -7 ;    // ASSERT: negative int NOT DATA_LOAD_IDX

// link messages
integer DATA_LOAD_IDX   = -420 ; // ASSERT: negative int
key     DATA_RETURN_EVT = "data" ;
integer N_PARAMS        = 4 ;
integer DESCRIPTION_IDX = 0 ; // ASSERT: FIXTURES strided index
integer REQUEST_IDX     = 1 ; // ASSERT: FIXTURES strided index
integer RESPONSE_IDX    = 2 ; // ASSERT: FIXTURES strided index
integer STATUS_IDX      = 3 ; // ASSERT: FIXTURES strided index
integer ENDPOINT_IDX    = 4 ;

// http status
integer HTTP_STATUS_SUCCESS  = 200 ;
integer HTTP_STATUS_REJECTED = 420 ;


/* state default functions */

integer loadSharedData(integer data_idx , string data)
{
  if (data == "") return FALSE ;

  if      (data_idx == GRID_IDX     ) GRID_NAME      = data ;
  else if (data_idx == REGION_IDX   ) REGION_NAME    = data ;
  else if (data_idx == PARCEL_IDX   ) PARCEL_NAME    = data ;
  else if (data_idx == SENTINEL_IDX ) ID_SENTINAL    = data ;
  else if (data_idx == EXCEPTION_IDX) EXCEPTION_RESP = data ;
  else if (data_idx == SECRET_IDX   ) SECRET_RESP    = data ;
  else if (data_idx == OWNER_IDX    ) OWNER_NAME     = data ;

  integer is_ready = GRID_NAME      != "" && REGION_NAME != "" &&
                     PARCEL_NAME    != "" && ID_SENTINAL != "" &&
                     EXCEPTION_RESP != "" && SECRET_RESP != "" &&
                     OWNER_NAME     != ""                       ;

  if (is_ready)
    CLIENT_NAME = llDumpList2String([ GRID_NAME , REGION_NAME , PARCEL_NAME ] , " ") ;

  return is_ready ;
}

prepareTestFixures()
{
  /* Client creation schema
  {
    client:
    {
      name:  "GridName Region_Name Parcel_Name" ,
      nicks: "NickA,NickB,NickC"                ,
      type:  'SimClient'
    }
  }
  */

  /* fixture stride schema
  [
    test description       .
    outgoing request JSON  ,
    expected response JSON ,
    expected status
  ]
  */


  /* fixtures */

  FIXTURES =
  [
    "should not CREATE Client with missing Client params"                                                      ,
    "{                                                                                                      }" ,
    EXCEPTION_RESP                                                                                             ,
    HTTP_STATUS_REJECTED                                                                                       ,

    "should not CREATE Client with empty Client params"                                                        ,
    "{ 'client': {}                                                                                         }" ,
    EXCEPTION_RESP                                                                                             ,
    HTTP_STATUS_REJECTED                                                                                       ,

    "should not CREATE Client with missing channel name"                                                       ,
    "{ 'client': {                                    'nicks': '" + OWNER_NAME + "' , 'type': 'SimClient' } }" ,
    EXCEPTION_RESP                                                                                             ,
    HTTP_STATUS_REJECTED                                                                                       ,

    "should not CREATE Client with empty channel name"                                                         ,
    "{ 'client': { 'name': ''                       , 'nicks': '" + OWNER_NAME + "' , 'type': 'SimClient' } }" ,
    EXCEPTION_RESP                                                                                             ,
    HTTP_STATUS_REJECTED                                                                                       ,

    "should not CREATE Client with missing nicks list"                                                         ,
    "{ 'client': { 'name': '" + CHANNEL_2_NAME + "'                                 , 'type': 'SimClient' } }" ,
    EXCEPTION_RESP                                                                                             ,
    HTTP_STATUS_REJECTED                                                                                       ,

    "should not CREATE Client with empty nicks list"                                                           ,
    "{ 'client': { 'name': '" + CHANNEL_2_NAME + "' , 'nicks': ''                   , 'type': 'SimClient' } }" ,
    EXCEPTION_RESP                                                                                             ,
    HTTP_STATUS_REJECTED                                                                                       ,

    "should not CREATE Client with missing client type"                                                        ,
    "{ 'client': { 'name': '" + CHANNEL_2_NAME + "' , 'nicks': '" + OWNER_NAME + "'                       } }" ,
    EXCEPTION_RESP                                                                                             ,
    HTTP_STATUS_REJECTED                                                                                       ,

    "should not CREATE Client with empty client type"                                                          ,
    "{ 'client': { 'name': '" + CHANNEL_2_NAME + "' , 'nicks': '" + OWNER_NAME + "' , 'type': ''          } }" ,
    EXCEPTION_RESP                                                                                             ,
    HTTP_STATUS_REJECTED                                                                                       ,

    "should     CREATE Client with valid params"                                                               ,
    "{ 'client': { 'name': '" + CHANNEL_2_NAME + "' , 'nicks': '" + OWNER_NAME + "' , 'type': 'SimClient' } }" ,
    SECRET_RESP                                                                                                ,
    HTTP_STATUS_SUCCESS                                                                                        ,

    "should not CREATE Client with duplicate channel name"                                                     ,
    "{ 'client': { 'name': '" + CHANNEL_2_NAME + "' , 'nicks': '" + OWNER_NAME + "' , 'type': 'SimClient' } }" ,
    DUPLICATES_RESP                                                                                            ,
    HTTP_STATUS_SUCCESS                                                                                        ] ;


  /* validation */

  if (llGetListLength(FIXTURES) % N_PARAMS) FIXTURES = [] ;
  N_FIXTURES = llGetListLength(FIXTURES) / N_PARAMS ;
}


/* helpers */

DBG_EVS(string msg) { if (DEBUG_EVS) llOwnerSay(msg) ; }

sendLinkMsg(integer data_idx , string data)
{
DBG_EVS("CLIENT::SEND    -> " + llList2CSV([DATA_RETURN_EVT , data_idx , data])) ;

  llMessageLinked(LINK_THIS , data_idx , data , DATA_RETURN_EVT) ;
}


default
{
  link_message(integer sender , integer data_idx , string data , key evt)
  {
    if (evt != SUITE_NAME) return ;

DBG_EVS("CLIENT::RECV    <- " + llList2CSV([evt , data_idx , data])) ;

    if (loadSharedData(data_idx , data)) { prepareTestFixures() ; state ready ; }
  }
}

state ready
{
  state_entry() { sendLinkMsg(DATA_LOAD_IDX , (string)N_FIXTURES) ; }

  link_message(integer sender , integer test_n , string unused , key evt)
  {
    if (evt != SUITE_NAME) return ;

DBG_EVS("CLIENT::RECV    <- " + llList2CSV([evt , test_n , unused])) ;

    integer is_valid_test_n = test_n >= 0 && test_n < N_FIXTURES ;
    integer offset_idx      = N_PARAMS * test_n ;

    if (is_valid_test_n)
    {
      string  description   = llList2String (FIXTURES , offset_idx + DESCRIPTION_IDX) ;
      string  request_json  = llList2String (FIXTURES , offset_idx + REQUEST_IDX    ) ;
      string  response_json = llList2String (FIXTURES , offset_idx + RESPONSE_IDX   ) ;
      integer status        = llList2Integer(FIXTURES , offset_idx + STATUS_IDX     ) ;

      sendLinkMsg(DESCRIPTION_IDX , description   ) ;
      sendLinkMsg(REQUEST_IDX     , request_json  ) ;
      sendLinkMsg(RESPONSE_IDX    , response_json ) ;
      sendLinkMsg(STATUS_IDX      , (string)status) ;
      sendLinkMsg(ENDPOINT_IDX    , RESOURCE_PATH ) ;
    }
    else state default ;
  }
}
